package de.bazinga.rotw.weapon.portal;

import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;

import com.jme.input.MouseInput;
import com.jme.intersection.PickData;
import com.jme.intersection.PickResults;
import com.jme.intersection.TrianglePickResults;
import com.jme.math.FastMath;
import com.jme.math.Quaternion;
import com.jme.math.Ray;
import com.jme.math.Vector3f;
import com.jme.scene.Geometry;
import com.jme.scene.Node;
import com.jme.scene.Spatial;
import com.jme.scene.shape.Box;
import com.jme.scene.state.CullState;
import com.jme.scene.state.ZBufferState;
import com.jmex.game.state.GameStateManager;
import com.jmex.terrain.TerrainBlock;

import de.bazinga.rotw.collision.CollidableObjects;
import de.bazinga.rotw.game.Game;
import de.bazinga.rotw.game.RotwGameState;
import de.bazinga.rotw.model.ModelCache;
import de.bazinga.rotw.person.Person;
import de.bazinga.rotw.player.Player;
import de.bazinga.rotw.sound.Sound;
import de.bazinga.rotw.weapon.Weapon;

public class PortalGun extends Weapon {
	
	
	private long lastShoot = 0;
	
	private EntryPortal entry = null;
	private Portal exit = null;
	
	protected static Node weaponModel = null;
	
	
	public PortalGun() {
		entry = new EntryPortal();
		PortalList.getInstance().addPortal(entry);
		
		exit = new Portal();
	}
	
	public void fireBullet(Person person, Vector3f location,
			Vector3f direction, boolean isEntry) {
		
		// Get New Location
		Ray ray = new Ray(location, direction);
//		PickResults results = new BoundingPickResults();
		PickResults results = new TrianglePickResults();
		results.setCheckDistance(true);
		
		// person.getParent() is the rootNode!
		TerrainBlock tb = ((RotwGameState)GameStateManager.getInstance().getChild("gameState")).getTerrainBlock();
		int size = (tb == null) ? 2:3;
		Spatial[] checkSpatials = new Spatial[size];
		checkSpatials[0] = CollidableObjects.getInstance().getObjects("portalWallNode").get(0);
		checkSpatials[1] = CollidableObjects.getInstance().getObjects("groundPortableNode").get(0);
		if(tb != null) checkSpatials[2] = tb;
		

		
		float distance = -5;
		int indexFound = 0;
		Geometry target = null;
		for(int i=0;i<checkSpatials.length;i++) {
			checkSpatials[i].findPick(ray,results);
			
			//check if we hit something
			if(results.getNumber() > 0) {
			   PickData closest = results.getPickData(0);

			   
			   if((distance < 0 || distance > closest.getDistance()) && !Float.isInfinite(closest.getDistance())) {
				   distance = closest.getDistance();
				   indexFound = i;
				   target = closest.getTargetMesh();
			   }

			}
		}

		if(distance > 0) {
			// We hit a wall or ground
			if(Game.getGame().getSettings().isSFX()) {
				Sound.getInstance().getAudioTrack("sounds/createPortal.wav").play();
			}
			
			if(isEntry) {
				entry.setLocalTranslation(
						location.add(
								direction.mult(
										distance-0.5f)));
				
				if(target instanceof Box) {
					faceBox(entry, (Box)target, location, entry.getLocalTranslation());
				}else if(indexFound == 2) {
					entry.lookAt(location, Vector3f.UNIT_Y);
				}else{
					entry.lookAt(location, Vector3f.UNIT_Y);
				}
			}else{
				Vector3f loc = location.add(
									direction.mult(
											distance));
				exit.setLocalTranslation(loc);
				
				
				if(target instanceof Box) {
					faceBox(exit,(Box)target, location, exit.getLocalTranslation());
				}else{
					exit.lookAt(location, Vector3f.UNIT_Y);
				}
				
				Vector3f dest = null;
				if(indexFound == 0) {
					// Wall
					dest = loc.subtract(
							direction.mult(new Vector3f(3,0,3)));
				}else if(indexFound == 2) {
					// Terrain
					dest = loc.clone();
					dest.setY(loc.getY()+2f);
				}else{
					// Ground
					
					dest = loc.clone();
					if(dest.getY() > person.getLocalTranslation().getY()) {
						dest.setY(loc.getY()-1f);
					}else{
						dest.setY(loc.getY()+1f);
					}
				}		
				
				exit.setDestLocation(dest);
				
				entry.setExitPortal(exit);
			}
		}
		
	}
	
	
	private void faceBox(Portal portal, Box b, Vector3f start, Vector3f end) {
		
		if(b.getXExtent() > b.getZExtent() && b.getYExtent() > b.getZExtent()) {
			portal.lookAt(portal.getLocalTranslation().add(new Vector3f(0,0,5)), Vector3f.UNIT_Y);
//			System.out.println("z small");
		}else if(b.getYExtent() > b.getXExtent() && b.getZExtent() > b.getXExtent()) {
//			System.out.println("x small");
			portal.lookAt(portal.getLocalTranslation().add(new Vector3f(5,0,0)), Vector3f.UNIT_Y);
		}else if(b.getXExtent() > b.getYExtent() && b.getZExtent() > b.getYExtent()) {
//			System.out.println("y small");
			portal.lookAt(portal.getLocalTranslation().add(new Vector3f(0,5,0)), Vector3f.UNIT_Y);
		}else if(b.getXExtent() == b.getYExtent() && b.getYExtent() == b.getZExtent()) {
			// All sides are the same
			portal.lookAt(start, Vector3f.UNIT_Y);
		}
	}
	
	public void addPortals(Node rootNode) {
		rootNode.attachChild(entry);
		rootNode.attachChild(exit);
	}
	
	public void reset() {
		getEntry().reset();
		getExit().reset();
	}

	public int getAmmo() {
		return 2;
	}

	public String getIcon() {
		return "portal.png";
	}

	public void refillAmmo() {
		
	}

	public void updateWeapon(Player player) {
		if( (System.currentTimeMillis() - lastShoot) < 500) return ;
		
		// Fire?
		if(MouseInput.get().isButtonDown(0)) {
			fireBullet(player,player.getCameraPosition().clone(),Game.getGame().getCamera().getDirection().clone(),true);
			lastShoot = System.currentTimeMillis();
		}else if(MouseInput.get().isButtonDown(1)) {
			fireBullet(player,player.getCameraPosition().clone(),Game.getGame().getCamera().getDirection().clone(),false);
			lastShoot = System.currentTimeMillis();
		}
	}

	
	public EntryPortal getEntry() {
		return entry;
	}

	public void setEntry(EntryPortal entry) {
		this.entry = entry;
	}

	public Portal getExit() {
		return exit;
	}

	public void setExit(Portal exit) {
		this.exit = exit;
	}
	

	
	public Node getWeaponModel() {
		if(weaponModel == null) {
			initWeaponModel();
		}
		return weaponModel;
	}
	
	public static void initWeaponModel() {
		if(weaponModel == null) {
			weaponModel = new Node("weapon");
			// Load Model
			URL textureUrl = null;
			try {
				textureUrl = new File("weapons/").toURI().toURL();
			} catch (MalformedURLException e1) {
				e1.printStackTrace();
			}
			Node weapon = ModelCache.getInstance().addModel(textureUrl, textureUrl, "/weapons/lazer.3ds");
			
	        weapon.setLocalScale(0.1f);
	        
	        
	        Quaternion rot = new Quaternion();
	        rot.fromAngleAxis(-90*FastMath.DEG_TO_RAD, Vector3f.UNIT_X);
	        weapon.setLocalRotation(rot);
	        
	        
	        
	        Node rotNode = new Node("rot");
	        rotNode.setLocalTranslation(new Vector3f(-0.7f,-0.5f,2));
	        rotNode.attachChild(weapon);
	        
	        Quaternion rot1 = new Quaternion();
	        rot1.fromAngleAxis(180*FastMath.DEG_TO_RAD, Vector3f.UNIT_Y);
	        rotNode.setLocalRotation(rot1);
	        

	        ZBufferState zBuffer = Game.getGame().getDisplay().getRenderer().createZBufferState();
	        zBuffer.setEnabled(true);
	        zBuffer.setFunction(ZBufferState.TestFunction.Always);
	        rotNode.setRenderState(zBuffer);
	        
	        CullState culling = Game.getGame().getDisplay().getRenderer().createCullState();
	        culling.setEnabled(true);
	        culling.setCullFace(CullState.Face.Back);
	        rotNode.setRenderState(culling);
	        
	        weaponModel.attachChild(rotNode);
	        weaponModel.updateRenderState();
	        
		}
	}
	
	
	public void playerFired() {
		
	}
	
	public float getSpeedFactor() {
		return 0.8f;
	}
	


	
	// We dont need this here
	public boolean reload() {
		return false;
	}
}
